/*-
 *   BSD LICENSE
 *
 *   Copyright (c) Intel Corporation.
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** \file
 * NVMe over Fabrics target public API
 */

#ifndef SPDK_NVMF_H
#define SPDK_NVMF_H

#include <stdint.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "nvmf_spec.h"

#include "core.h"
#include "cache.h"
#include "lich_id.h"

#define MAX_VIRTUAL_NAMESPACE 16
#define MAX_SN_LEN 20

#define nvmf_min(a,b) (((a)<(b))?(a):(b))
#define nvmf_max(a,b) (((a)>(b))?(a):(b))

int lich_nvmf_tgt_init(void);

int lich_nvmf_tgt_fini(void);


struct lich_nvmf_subsystem;
struct lich_nvmf_session;
struct lich_nvmf_conn;
struct lich_nvmf_request;
struct lich_nvme_ctrlr;
struct lich_nvmf_request;
struct lich_nvmf_conn;

typedef void (*lich_nvmf_subsystem_connect_fn)(void *cb_ctx, struct lich_nvmf_request *req);
typedef void (*lich_nvmf_subsystem_disconnect_fn)(void *cb_ctx, struct lich_nvmf_conn *conn);

enum lich_nvmf_subsystem_mode {
	NVMF_SUBSYSTEM_MODE_DIRECT	= 0,
	NVMF_SUBSYSTEM_MODE_VIRTUAL	= 1,
};

struct lich_nvmf_listen_addr {
	struct in_addr   	traddr;
	char                    *trsvcid;
	char                    *trname;

	struct list_head	link;
};

struct lich_nvmf_host {
	char				*nqn;

        struct list_head                link;
};

struct lich_nvmf_ctrlr_ops {
	/**
	 * Get NVMe identify controller data.
	 */
	void (*ctrlr_get_data)(struct lich_nvmf_session *session);

	/**
	 * Process admin command.
	 */
	int (*process_admin_cmd)(struct lich_nvmf_request *req);

	/**
	 * Process IO command.
	 */
	int (*process_io_cmd)(struct lich_nvmf_request *req);

	/**
	 * Poll for completions.
	 */
	void (*poll_for_completions)(struct lich_nvmf_session *session);

	/**
	 * Detach the controller.
	 */
	void (*detach)(struct lich_nvmf_subsystem *subsystem);
};

/*
 * The NVMf subsystem, as indicated in the specification, is a collection
 * of virtual controller sessions.  Any individual controller session has
 * access to all the NVMe device/namespaces maintained by the subsystem.
 */
struct lich_nvmf_subsystem {
        int lcore;
        char subnqn[SPDK_NVMF_NQN_MAX_LEN];
        enum lich_nvmf_subsystem_mode mode;
        enum spdk_nvmf_subtype subtype;


        struct {
                char	sn[MAX_SN_LEN + 1];
                //ns_info_t *ns_list[MAX_VIRTUAL_NAMESPACE];
                ns_info_t *ns_list;
                //mcache_entry_t *entry[MAX_VIRTUAL_NAMESPACE];
                uint16_t ns_count;
        }dev;

        const struct lich_nvmf_ctrlr_ops *ops;

        void					*cb_ctx;
	lich_nvmf_subsystem_connect_fn		connect_cb;
	lich_nvmf_subsystem_disconnect_fn	disconnect_cb;

        struct list_head                        sessions;
        uint32_t				session_id;

        struct list_head                        listen_addrs;
        uint32_t				num_listen_addrs;

        struct list_head                        hosts;
	uint32_t				num_hosts;

        struct list_head                        entries;
};

struct lich_nvmf_subsystem *lich_nvmf_create_subsystem(int core_hash, const char *nqn,
		enum spdk_nvmf_subtype type,
		enum lich_nvmf_subsystem_mode mode,
		void *cb_ctx,
		lich_nvmf_subsystem_connect_fn connect_cb,
		lich_nvmf_subsystem_disconnect_fn disconnect_cb);

void lich_nvmf_delete_subsystem(struct lich_nvmf_subsystem *subsystem);

struct lich_nvmf_subsystem *nvmf_find_subsystem(const char *subnqn);

struct lich_nvmf_subsystem *nvmf_get_subsystem(int core_hash);

bool lich_nvmf_subsystem_exists(const char *subnqn);

bool lich_nvmf_subsystem_host_allowed(struct lich_nvmf_subsystem *subsystem, const char *hostnqn);

int lich_nvmf_subsystem_add_listener(struct lich_nvmf_subsystem *subsystem,
				 char *trname, u_long traddr, char *trsvcid);

int lich_nvmf_subsystem_add_host(struct lich_nvmf_subsystem *subsystem,
			     char *host_nqn);

void lich_nvmf_subsystem_poll(struct lich_nvmf_subsystem *subsystem);

int lich_nvmf_subsystem_add_ns(struct lich_nvmf_subsystem *subsystem, nvmf_ns_t *ns);

int lich_nvmf_subsystem_set_sn(struct lich_nvmf_subsystem *subsystem, const char *sn);

const char *lich_nvmf_subsystem_get_nqn(struct lich_nvmf_subsystem *subsystem);
enum spdk_nvmf_subtype lich_nvmf_subsystem_get_type(struct lich_nvmf_subsystem *subsystem);
enum lich_nvmf_subsystem_mode lich_nvmf_subsystem_get_mode(struct lich_nvmf_subsystem *subsystem);

void lich_nvmf_acceptor_poll(void);

void lich_nvmf_handle_connect(struct lich_nvmf_request *req);

void lich_nvmf_session_disconnect(struct lich_nvmf_conn *conn);

int nvmf_core_subsystem_init(core_t *core);

void lich_strcpy_pad(void *dst, const char *src, size_t size, int pad);

void nvmf_rdma_buf_dereg_mgr(struct lich_nvmf_conn *conn);

int lich_get_rdma_capsule_data_size();

int core_map_update();

nvmf_ns_t *core_map_get_ns(int core_id);

struct lich_nvmf_subsystem *lich_nvmf_find_subsystem_with_cntlid(uint16_t cntlid);
#endif
